import BaseMiddleware from './BaseMiddleware.js';
import { config } from '../config.js';

/**
 * 限流中间件 - 防止API滥用和保护服务器资源
 */
export class RateLimitingMiddleware extends BaseMiddleware {
    constructor(options = {}) {
        super({
            priority: 20, // 较高优先级，在认证之前执行
            windowMs: 15 * 60 * 1000, // 15分钟窗口
            maxRequests: 100, // 每个窗口最大请求数
            keyGenerator: null, // 自定义键生成器
            skipPaths: ['/health', '/favicon.ico'],
            skipSuccessfulRequests: false, // 是否跳过成功请求的计数
            skipFailedRequests: false, // 是否跳过失败请求的计数
            enableHeaders: true, // 是否添加限流头信息
            message: 'Too many requests, please try again later.',
            statusCode: 429,
            standardHeaders: true, // 使用标准的RateLimit头
            legacyHeaders: false, // 使用传统的X-RateLimit头
            store: 'memory', // 存储类型：memory, redis
            onLimitReached: null, // 达到限制时的回调
            ...options
        });
        
        // 内存存储
        this.memoryStore = new Map();
        
        // 不同类型的限流配置
        this.rateLimitConfigs = {
            // 全局限流
            global: {
                windowMs: this.options.windowMs,
                maxRequests: this.options.maxRequests
            },
            // 按IP限流
            ip: {
                windowMs: 15 * 60 * 1000, // 15分钟
                maxRequests: 100
            },
            // 按用户限流
            user: {
                windowMs: 15 * 60 * 1000, // 15分钟
                maxRequests: 200 // 认证用户更高限制
            },
            // 按API端点限流
            endpoint: {
                windowMs: 60 * 1000, // 1分钟
                maxRequests: 30
            },
            // 登录限流
            login: {
                windowMs: 15 * 60 * 1000, // 15分钟
                maxRequests: 5 // 登录尝试限制
            },
            // 注册限流
            register: {
                windowMs: 60 * 60 * 1000, // 1小时
                maxRequests: 3 // 注册限制
            }
        };
        
        // 定期清理过期记录
        this.startCleanupTimer();
    }

    /**
     * 执行限流检查
     * @param {Request} req - Express请求对象
     * @param {Response} res - Express响应对象
     * @param {Function} next - Express next函数
     */
    async execute(req, res, next) {
        // 跳过指定路径
        if (this.shouldSkipRequest(req)) {
            return next();
        }

        try {
            // 生成限流键
            const key = this.generateKey(req);
            
            // 获取限流配置
            const config = this.getRateLimitConfig(req);
            
            // 检查限流
            const result = await this.checkRateLimit(key, config, req);
            
            // 添加响应头
            if (this.options.enableHeaders) {
                this.addRateLimitHeaders(res, result, config);
            }
            
            // 检查是否超出限制
            if (result.exceeded) {
                return this.handleRateLimitExceeded(req, res, result, config);
            }
            
            // 记录请求
            await this.recordRequest(key, config, req, res);
            
            next();
        } catch (error) {
            console.error('[RateLimitingMiddleware] Error:', error);
            // 限流错误时允许请求通过，避免服务中断
            next();
        }
    }

    /**
     * 检查限流状态
     * @param {string} key - 限流键
     * @param {Object} config - 限流配置
     * @param {Request} req - Express请求对象
     * @returns {Object} 限流检查结果
     */
    async checkRateLimit(key, config, req) {
        const now = Date.now();
        const windowStart = now - config.windowMs;
        
        // 获取或创建记录
        let record = this.memoryStore.get(key);
        if (!record) {
            record = {
                requests: [],
                windowStart: now,
                totalHits: 0
            };
            this.memoryStore.set(key, record);
        }
        
        // 清理过期请求
        record.requests = record.requests.filter(timestamp => timestamp > windowStart);
        
        // 计算当前请求数
        const currentRequests = record.requests.length;
        const remaining = Math.max(0, config.maxRequests - currentRequests);
        const exceeded = currentRequests >= config.maxRequests;
        
        // 计算重置时间
        const oldestRequest = record.requests[0];
        const resetTime = oldestRequest ? new Date(oldestRequest + config.windowMs) : new Date(now + config.windowMs);
        
        return {
            key,
            exceeded,
            totalHits: record.totalHits,
            totalRequests: currentRequests,
            remaining,
            resetTime,
            windowMs: config.windowMs,
            maxRequests: config.maxRequests
        };
    }

    /**
     * 记录请求
     * @param {string} key - 限流键
     * @param {Object} config - 限流配置
     * @param {Request} req - Express请求对象
     * @param {Response} res - Express响应对象
     */
    async recordRequest(key, config, req, res) {
        const record = this.memoryStore.get(key);
        if (!record) return;
        
        // 监听响应完成
        res.on('finish', () => {
            const shouldCount = this.shouldCountRequest(req, res);
            if (shouldCount) {
                const now = Date.now();
                record.requests.push(now);
                record.totalHits++;
                
                // 记录日志
                this.logRequest(key, record, req, res);
            }
        });
    }

    /**
     * 处理限流超出情况
     * @param {Request} req - Express请求对象
     * @param {Response} res - Express响应对象
     * @param {Object} result - 限流检查结果
     * @param {Object} config - 限流配置
     */
    async handleRateLimitExceeded(req, res, result, config) {
        // 调用回调函数
        if (this.options.onLimitReached) {
            try {
                await this.options.onLimitReached(req, res, result);
            } catch (error) {
                console.error('[RateLimitingMiddleware] onLimitReached callback error:', error);
            }
        }
        
        // 记录限流日志
        this.logRateLimitExceeded(req, result);
        
        // 发送限流响应
        const response = {
            success: false,
            message: this.options.message,
            statusCode: this.options.statusCode,
            rateLimit: {
                limit: result.maxRequests,
                remaining: result.remaining,
                resetTime: result.resetTime.toISOString(),
                retryAfter: Math.ceil(result.windowMs / 1000)
            },
            timestamp: new Date().toISOString()
        };
        
        res.status(this.options.statusCode).json(response);
    }

    /**
     * 添加限流响应头
     * @param {Response} res - Express响应对象
     * @param {Object} result - 限流检查结果
     * @param {Object} config - 限流配置
     */
    addRateLimitHeaders(res, result, config) {
        if (this.options.standardHeaders) {
            // 标准RateLimit头 (RFC 6585)
            res.set({
                'RateLimit-Limit': config.maxRequests.toString(),
                'RateLimit-Remaining': result.remaining.toString(),
                'RateLimit-Reset': result.resetTime.toISOString()
            });
            
            if (result.exceeded) {
                res.set('Retry-After', Math.ceil(config.windowMs / 1000).toString());
            }
        }
        
        if (this.options.legacyHeaders) {
            // 传统X-RateLimit头
            res.set({
                'X-RateLimit-Limit': config.maxRequests.toString(),
                'X-RateLimit-Remaining': result.remaining.toString(),
                'X-RateLimit-Reset': Math.ceil(result.resetTime.getTime() / 1000).toString()
            });
        }
    }

    /**
     * 生成限流键
     * @param {Request} req - Express请求对象
     * @returns {string} 限流键
     */
    generateKey(req) {
        if (this.options.keyGenerator) {
            return this.options.keyGenerator(req);
        }
        
        // 默认键生成策略：IP + 用户ID（如果有）
        const ip = this.getClientIP(req);
        const userId = req.user?.userId || req.user?.id;
        
        if (userId) {
            return `user:${userId}:${ip}`;
        }
        
        return `ip:${ip}`;
    }

    /**
     * 获取限流配置
     * @param {Request} req - Express请求对象
     * @returns {Object} 限流配置
     */
    getRateLimitConfig(req) {
        const path = req.path.toLowerCase();
        
        // 特殊端点限流
        if (path.includes('/login') || path.includes('/auth/login')) {
            return this.rateLimitConfigs.login;
        }
        
        if (path.includes('/register') || path.includes('/auth/register')) {
            return this.rateLimitConfigs.register;
        }
        
        // 认证用户使用更高限制
        if (req.user) {
            return this.rateLimitConfigs.user;
        }
        
        // 默认IP限流
        return this.rateLimitConfigs.ip;
    }

    /**
     * 判断是否应该跳过请求
     * @param {Request} req - Express请求对象
     * @returns {boolean} 是否跳过
     */
    shouldSkipRequest(req) {
        return this.options.skipPaths.some(path => {
            if (typeof path === 'string') {
                return req.path === path;
            } else if (path instanceof RegExp) {
                return path.test(req.path);
            }
            return false;
        });
    }

    /**
     * 判断是否应该计数请求
     * @param {Request} req - Express请求对象
     * @param {Response} res - Express响应对象
     * @returns {boolean} 是否计数
     */
    shouldCountRequest(req, res) {
        const isSuccessful = res.statusCode < 400;
        const isFailed = res.statusCode >= 400;
        
        if (this.options.skipSuccessfulRequests && isSuccessful) {
            return false;
        }
        
        if (this.options.skipFailedRequests && isFailed) {
            return false;
        }
        
        return true;
    }

    /**
     * 记录请求日志
     * @param {string} key - 限流键
     * @param {Object} record - 限流记录
     * @param {Request} req - Express请求对象
     * @param {Response} res - Express响应对象
     */
    logRequest(key, record, req, res) {
        if (config.env === 'development') {
            console.log(`[RateLimitingMiddleware] Request recorded - Key: ${key}, Total: ${record.totalHits}, Current: ${record.requests.length}`);
        }
    }

    /**
     * 记录限流超出日志
     * @param {Request} req - Express请求对象
     * @param {Object} result - 限流检查结果
     */
    logRateLimitExceeded(req, result) {
        console.warn(`[RateLimitingMiddleware] Rate limit exceeded - Key: ${result.key}, IP: ${this.getClientIP(req)}, Path: ${req.path}`);
    }

    /**
     * 启动清理定时器
     */
    startCleanupTimer() {
        // 每5分钟清理一次过期记录
        setInterval(() => {
            this.cleanupExpiredRecords();
        }, 5 * 60 * 1000);
    }

    /**
     * 清理过期记录
     */
    cleanupExpiredRecords() {
        const now = Date.now();
        let cleanedCount = 0;
        
        for (const [key, record] of this.memoryStore.entries()) {
            // 清理过期请求
            const originalLength = record.requests.length;
            record.requests = record.requests.filter(timestamp => 
                now - timestamp < Math.max(...Object.values(this.rateLimitConfigs).map(c => c.windowMs))
            );
            
            // 如果没有活跃请求，删除记录
            if (record.requests.length === 0) {
                this.memoryStore.delete(key);
                cleanedCount++;
            }
        }
        
        if (cleanedCount > 0 && config.env === 'development') {
            console.log(`[RateLimitingMiddleware] Cleaned up ${cleanedCount} expired records`);
        }
    }

    /**
     * 获取客户端IP地址
     * @param {Request} req - Express请求对象
     * @returns {string} IP地址
     */
    getClientIP(req) {
        return req.ip || 
               req.connection?.remoteAddress || 
               req.socket?.remoteAddress || 
               req.headers['x-forwarded-for']?.split(',')[0]?.trim() ||
               req.headers['x-real-ip'] ||
               '127.0.0.1';
    }

    /**
     * 获取限流统计信息
     * @returns {Object} 限流统计
     */
    getRateLimitStats() {
        const stats = {
            totalKeys: this.memoryStore.size,
            activeRequests: 0,
            keyDetails: []
        };
        
        for (const [key, record] of this.memoryStore.entries()) {
            stats.activeRequests += record.requests.length;
            stats.keyDetails.push({
                key,
                totalHits: record.totalHits,
                activeRequests: record.requests.length,
                windowStart: new Date(record.windowStart).toISOString()
            });
        }
        
        return stats;
    }

    /**
     * 重置限流统计
     * @param {string} key - 可选的特定键，如果不提供则重置所有
     */
    resetRateLimit(key = null) {
        if (key) {
            this.memoryStore.delete(key);
            console.log(`✓ Rate limit reset for key: ${key}`);
        } else {
            this.memoryStore.clear();
            console.log('✓ All rate limits reset');
        }
    }

    /**
     * 更新限流配置
     * @param {string} type - 配置类型
     * @param {Object} config - 新配置
     */
    updateRateLimitConfig(type, config) {
        if (this.rateLimitConfigs[type]) {
            this.rateLimitConfigs[type] = { ...this.rateLimitConfigs[type], ...config };
            console.log(`✓ Rate limit config updated for type: ${type}`);
        } else {
            console.warn(`Unknown rate limit config type: ${type}`);
        }
    }

    /**
     * 创建特定配置的限流中间件
     * @param {Object} config - 限流配置
     * @returns {Function} Express中间件函数
     */
    static createRateLimit(config = {}) {
        const rateLimiter = new RateLimitingMiddleware(config);
        return rateLimiter.getMiddleware();
    }

    /**
     * 创建严格限流中间件（用于敏感操作）
     * @param {Object} options - 配置选项
     * @returns {Function} Express中间件函数
     */
    static createStrictRateLimit(options = {}) {
        return RateLimitingMiddleware.createRateLimit({
            windowMs: 15 * 60 * 1000, // 15分钟
            maxRequests: 5, // 严格限制
            message: 'Too many attempts, please try again later.',
            ...options
        });
    }

    /**
     * 创建API限流中间件
     * @param {Object} options - 配置选项
     * @returns {Function} Express中间件函数
     */
    static createAPIRateLimit(options = {}) {
        return RateLimitingMiddleware.createRateLimit({
            windowMs: 15 * 60 * 1000, // 15分钟
            maxRequests: 100,
            keyGenerator: (req) => {
                // API密钥优先，否则使用IP
                const apiKey = req.headers['x-api-key'];
                if (apiKey) {
                    return `api:${apiKey}`;
                }
                return `ip:${req.ip}`;
            },
            ...options
        });
    }
}

// 创建默认实例
export const rateLimitingMiddleware = new RateLimitingMiddleware();

// 导出便捷方法
export const rateLimit = (options = {}) => new RateLimitingMiddleware(options).getMiddleware();
export const strictRateLimit = RateLimitingMiddleware.createStrictRateLimit;
export const apiRateLimit = RateLimitingMiddleware.createAPIRateLimit;

export default RateLimitingMiddleware;